package com.bioscript.standalone.IO;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.w3c.dom.DOMConfiguration;
import org.w3c.dom.Document;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;

import com.bioscript.standalone.dataStructures.BlastHit;

public class FileWriter {
	
	public static boolean writeGff3File(String database, Map<String, List<BlastHit>> map, String fileName, String seqName, String seqSize)
	{
		List<String> lst = new ArrayList<String>();
		lst.add("##gff-version 3");
		String attribute = String.format("ID=%s;Name=%s",seqName,seqName);
//		String row = String.format("##sequence-region %s %s %s\n%s\t%s\t%s\t%s\t%s\t%s\t.\t.\t%s",
//				seqName,1,seqSize,seqName,
//				database,"contig",
//				1,seqSize,".",attribute);
		String row = String.format("##sequence-region %s %s %s\n",
				seqName,1,seqSize);
		lst.add(row);
		int index = 0 ;
		Set<String> keySet = map.keySet();
		for(String geneName : keySet)
		{
			int hitIndex = 0;
			List<BlastHit> hitsList = map.get(geneName);
			for(BlastHit hit : hitsList)
			{
				String newGeneName = geneName;
				if (hitsList.size() > 1)
					newGeneName = newGeneName + "_" + hitIndex;
				// create the attribute string as follows:
				// PARENT=PARENT ID=MATCH<indexOfGene> NAME=<nameOfTheGene> eVal=<e-value of he match>
				// mM=<number of mismaches in the match> gaps=<number of gaps encountered in the match>
				attribute = String.format
				("ID=MATCH%s;Name=%s;eVal=%s;mM=%s;gaps=%s;gStart=%s;gEnd=%s",
						index,hit.getQuery().getName(),hit.geteVal(),
						hit.getMismatches(),hit.getGapOpenings(),
						hit.getQuery().getLowerLimit(), hit.getQuery().getUpperLimit());
				if (hit.getSource().getLowerLimit() > hit.getSource().getUpperLimit())
				{
					row = (String.format("%s\t%s\tgene\t%s\t%s\t%s\t-\t.\t%s",
							newGeneName,database,hit.getSource().getUpperLimit()
							, hit.getSource().getLowerLimit(), hit.getIdentity(),
							attribute));
				}
				else
				{
					row = (String.format("%s\t%s\tgene\t%s\t%s\t%s\t+\t.\t%s",
							newGeneName,database,hit.getSource().getLowerLimit()
							, hit.getSource().getUpperLimit(), hit.getIdentity(),
							attribute));
				}
				hitIndex++;
				lst.add(row);
				index++;
			}
		}
		
		
//		for(BlastHit hit : map)
//		{
//			// create the attribute string as follows:
//			// PARENT=PARENT ID=MATCH<indexOfGene> NAME=<nameOfTheGene> eVal=<e-value of he match>
//			// mM=<number of mismaches in the match> gaps=<number of gaps encountered in the match>
//			attribute = String.format
//			("ID=MATCH%s;Name=%s;eVal=%s;mM=%s;gaps=%s;gStart=%s;gEnd=%s",
//					index,hit.getQuery().getName(),hit.geteVal(),
//					hit.getMismatches(),hit.getGapOpenings(),
//					hit.getQuery().getLowerLimit(), hit.getQuery().getUpperLimit());
//			if (hit.getSource().getLowerLimit() > hit.getSource().getUpperLimit())
//			{
//				row = (String.format("%s\t%s\tgene\t%s\t%s\t%s\t-\t.\t%s",
//						seqName,database,hit.getSource().getUpperLimit()
//						, hit.getSource().getLowerLimit(), hit.getIdentity(),
//						attribute));
//			}
//			else
//			{
//				row = (String.format("%s\t%s\tgene\t%s\t%s\t%s\t+\t.\t%s",
//						seqName,database,hit.getSource().getLowerLimit()
//						, hit.getSource().getUpperLimit(), hit.getIdentity(),
//						attribute));
//			}
//			
//			lst.add(row);
//			index++;
//		}
		return writeToFile(fileName, lst);
	}
	public static boolean writeToFile(String fileName, List<String> lst) 
	{
		try
		{
			PrintWriter pw = new PrintWriter(fileName);
			for(String str : lst)
			{
				pw.println(str);
			}
			pw.flush();
			pw.close();
			return true;
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return false;
	}
	
	public static String makeXMLString(Document doc)
	{
		try
		{
			DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
			DOMImplementationLS impl = 
			    (DOMImplementationLS)registry.getDOMImplementation("LS");
			LSSerializer writer = impl.createLSSerializer();
			DOMConfiguration configuration = writer.getDomConfig();
			configuration.setParameter("format-pretty-print", Boolean.TRUE);
			configuration.setParameter("xml-declaration", Boolean.FALSE);
			LSOutput output = impl.createLSOutput();
			StringWriter stringWriter = new StringWriter();
			output.setCharacterStream(stringWriter);
			writer.write(doc, output);
			return stringWriter.toString();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return null;
	}
	
	public static boolean writeXML(Document doc , String fileName)
	{
		try
		{
			DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
			DOMImplementationLS impl = 
			    (DOMImplementationLS)registry.getDOMImplementation("LS");
			LSSerializer writer = impl.createLSSerializer();
			writer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE);
			LSOutput output = impl.createLSOutput();
			FileOutputStream fos = new FileOutputStream(new File(fileName));
			output.setByteStream(fos);
			writer.write(doc, output);
			fos.close();
			return true;
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return false;
	}
}
